<?php
namespace Tbf\Util;
/**
 * 二维数据
 *   id 节点id
 *   parent_id 父节点id
 *   父节点为0是根节点。
 *   child_id
 * array(
 *      1 => array('id'=>'1','parent_id'=>0,'name'=>'一级栏目一','..'=>'..'),
 *      2 => array('id'=>'2','parent_id'=>0,'name'=>'一级栏目二'),
 *      3 => array('id'=>'3','parent_id'=>1,'name'=>'二级栏目一'),
 *      4 => array('id'=>'4','parent_id'=>1,'name'=>'二级栏目二'),
 *      5 => array('id'=>'5','parent_id'=>2,'name'=>'二级栏目三'),
 *      6 => array('id'=>'6','parent_id'=>3,'name'=>'三级栏目一'),
 *      7 => array('id'=>'7','parent_id'=>3,'name'=>'三级栏目二')
 *      )
 * 内部使用树状数据
 * 不容易看明白，容易从根开始遍历。
 * array(
 *      0 => array('child_id'=>array(1,2)),
 *      1 => array('id'=>'1','parent_id'=>0,'name'=>'一级栏目一','child_id'=>array(3,4)),
 *      2 => array('id'=>'2','parent_id'=>0,'name'=>'一级栏目二','child_id'=>array(5)),
 *      3 => array('id'=>'3','parent_id'=>1,'name'=>'二级栏目一','child_id'=>array(6,7)),
 *      4 => array('id'=>'4','parent_id'=>1,'name'=>'二级栏目二','child_id'=>array()),
 *      5 => array('id'=>'5','parent_id'=>2,'name'=>'二级栏目三','child_id'=>array()),
 *      6 => array('id'=>'6','parent_id'=>3,'name'=>'三级栏目一','child_id'=>array()),
 *      7 => array('id'=>'7','parent_id'=>3,'name'=>'三级栏目二','child_id'=>array())
 *      )
 */
/**
 * @deprecated
 */
class TreeUtil
{
    private $hasChildId = false;
    protected $tree = array();
    protected $maxDepth = 100;
    /**
     * 构造函数，初始化类
     * @param array 2维数组，例如：
     * array(
     *      1 => array('id'=>'1','parent_id'=>0,'name'=>'一级栏目一'),
     *      2 => array('id'=>'2','parent_id'=>0,'name'=>'一级栏目二'),
     *      3 => array('id'=>'3','parent_id'=>1,'name'=>'二级栏目一'),
     *      4 => array('id'=>'4','parent_id'=>1,'name'=>'二级栏目二'),
     *      5 => array('id'=>'5','parent_id'=>2,'name'=>'二级栏目三'),
     *      6 => array('id'=>'6','parent_id'=>3,'name'=>'三级栏目一'),
     *      7 => array('id'=>'7','parent_id'=>3,'name'=>'三级栏目二')
     *      )
     */
    public function __construct($array)
    {
        $this->tree = $array;
    }
    public function maxDepth($depth)
    {
        $this->maxDepth = $depth;
    }
    /*
     * 返回全部数据，不包含第一个虚拟根。。。
     */
    public function getData()
    {
        $data = $this->tree;
        unset($data[0]);

        return $data;
    }
    /**
     * 使用某字段重新写数据的key
      @param array $data
      @param string $keyName
     */
    public function reKeyById()
    {
        $this->tree = ArrayUtil::reKeyById($this->tree);

        return $this;
    }
    /**
     * 获取字节点id
     */
    public function loadChildId()
    {
        if ($this->hasChildId) {
            return ;
        }
        $array = $this->tree;
        //全部写入初始数据。
        foreach ($array as $id=>$row) {
            $array[$id]['child_id'] = array();
        }
        //生成子节点列表。
        foreach ($array as $id=>$row) {
            if (!isset($row['parent_id'])) {
                continue;
            }
            $array[$row['parent_id']]['child_id'][] = $id;
        }
        $this->tree = $array;
        $this->hasChildId = true;

        return $this;
    }
    /**
     * 重新排序
     * 并加入节点深度信息。
     */
    public function reOrder()
    {
        $this->loadChildId();
        if (empty($this->tree[0])) {
            return;
        }
        $_this = $this;
        $newArray = array();
        $newArray[0] = $this->tree[0];
        $this->renderCallBack(function($row,$next,$level) use ($_this,&$newArray) {
            $row['level'] = $level;
            $newArray[$row['id']] = $row;
            if ($next) {
                $next();
            }
        });
        $this->tree = $newArray;

        return $this;
    }
    /**
     * 树状渲染,使用回调确定渲染方法。
     回调格式
     func ($row,$childCb,$level)
     $row 数据
     $childCb 字节点回调，没有输入参数，可以echo出数据，也可以返回数据。
     $level 树状层次 从1开始
     echo出数据的，数据会被echo出，返回数据的数据会被返回。
     */
    public function renderCallBack($cb)
    {
        $this->loadChildId();
        $array = $this->tree;
        if (empty($array[0])) {
            return '';
        }
        $output = '';
        foreach ($array[0]['child_id'] as $child_id) {
            $output .= $this->renderCallBackHelper($cb,$child_id,1);
        };

        return $output;
    }
    /**
     * 添加全称
     * full_name
     * 一级栏目一-二级栏目一-三级栏目一
     */
    public function fullName($a='-')
    {
        foreach ($this->tree as &$v1) {
            if (empty($v1['parent_id'])) {
                continue;
            }
            $parent_id = $v1['parent_id'];
            $v1['full_name'] = $v1['name'];
            $depth = 0;
            while ($parent_id) {
                if (empty($this->tree[$parent_id])) {
                    break;
                }
                $depth+=1;
                if ($this->maxDepth!==0&&$depth>$this->maxDepth) {
                    break;
                }
                $v1['full_name'] = $this->tree[$parent_id]['name'].$a.$v1['full_name'];
                $parent_id = $this->tree[$parent_id]['parent_id'];
            }
        }
        unset($v1);

        return $this;
    }
    /**
     * 添加树状名称
     * 这个函数会重新排序数组
     * 必须按照输出的顺序循环才能看到效果。。
     * tree_name
     */
    public function treeName($data = null)
    {
        $this->loadChildId();
        $default = array('│','├','└','<b></b>');
        if ($data===null) {
            $data = $default;
        }
        $totalNum = count($this->tree);
        if ($totalNum==0) {
            return $this;
        }
        $this->tmp = array();
        $this->tmp[0] = $this->tree[0];
        $this->treeNameHelper($data,0);
        $this->tree = $this->tmp;

        return $this;
    }

    protected function treeNameHelper($icon , $myid, $adds = '')
    {
        $number = 1;
        if (empty($this->tree[$myid])) {
            //数据关联错误
            return array();
        }
        $child = $this->tree[$myid]['child_id'];
        if (empty($child)) {
            return array();
        }
        $total = count($child);
        $nbsp = $icon[3];
        foreach ($child as $id) {
            $j=$k='';
            if ($number==$total) {
                $j = $icon[2];  //└
            } else {
                $j = $icon[1];  //├
                if ($adds) {
                    $k = $icon[0] ; //│
                }
            }
            if ($adds) {
                $tree_name = $adds.$j ;
            } else {
                $tree_name = '';
            }
            $row = $this->tree[$id];
            $row['tree_name'] = $tree_name.$row['name'];
            $this->tmp[$id] = $row;
            $ret1 = $this->treeNameHelper($icon,$id, $adds.$k.$nbsp);
            $number++;
        }

        return ;

    }
    /**
     * 需要递归
     */
    public function renderCallBackHelper($cb,$id=0,$level=1)
    {
        $array = $this->tree;
        $output = '';
        $row = $array[$id];
        if (!empty($row['child_id'])) {
            $_this = $this;
            $newcb = function() use ($row,$array,$cb,$level,$_this) {
                $output = '';
                foreach ($row['child_id'] as $child_id) {
                    $output .= $_this->renderCallBackHelper($cb,$child_id,$level+1);
                }

                return $output;
            };
        } else {
            $newcb = null;
        }

        return $cb($row,$newcb,$level);
    }//function
}//class
